请求方式
OkHttp支持同步和异步的Http请求
同步和异步请求的代码如下:
1 | private final static OkHttpClient client = new OkHttpClient.Builder() |
OkHttpClient使用Builder模式来为其配置众多的参数
1 | public static final class Builder { |
OkHttpClient通过build创建完实例后,就包含了众多的参数
创建请求
用户的请求是通过一个Request来描述的,它一般的构造形式如下:
1 |
|
同样的Request也是通过Builder来创建构造实例的,它只是封装了HTTP请求需要的一些信息。Okhttp通过newCall来为我们的请求创建一个Call对象,这个对象负责为Request服务来完成一次Http请求过程
1 | public Call newCall(Request request) { |
发起请求
接着我们看看RealCall的实现
1 | //同步的请求 |
同步请求是通过RealCall的execute发起的,它的实现也很简单,首先置executed为true表示Call已经发起执行,若再次使用该Call发起请求会抛出Already Executed异常随后通过OkHttpClient配置的dispatcher执行executed,这个Dispatcher是请求的派发策略,说白了就是发起的请求,无论是异步的还是同步都要通过该Dispatcher进行一些设置。对于同步的请求,dispatcher会将该请求记录到一个同步请求队列中,请求完成后通过finished方法将其移除,而对于异步的请求Dispatcher会将该请求任务添加到异步请求队列中,并通过线程池来发起真正的请求。这里需要注意对于异步请求它的Call为AsyncCall。
1 | public final class Dispatcher { |
那么对于同步请求来说,在RealCall的execute方法中真正执行请求过程的必然是通过getResponseWithInterceptorChain来实现的,通过方法名称我们也能知道。而异步请求是在AysnCall的回调中进行的,我们看看AsynCall的实现
1 | public abstract class NamedRunnable implements Runnable { |
对于异步请求来说,在ASyncCall的回调方法中同样是通过getResponseWithInterceptorChain(forWebSocket)来完成HTTP的请求过程,随后通过responseCallback将请求结果返回给上层应用最后通过dispatcher的finished方法将Call从异步队列中移除。
请求过程
前面我们知道了无论是同步还是异步的请求最终都是通过getResponseWithInterceptorChain方法来完成请求过程的,接下来我们将分析请求过程的具体实现
1 | final class RealCall implements Call { |
从getResponseWithInterceptorChain中我们并没有看到实际的请求过程是如何进行的,它内部维护了一个拦截器列表,这个列表首先添加OkHttpClient配置的应用拦截器,然后添加内置的几个拦截器,最后添加网络拦截器和CallServerInterceptor拦截器,然后通过这个拦截器列表构造一个RealInterceptorChain并调用processd来执行请求过程。那么拦截器在这之间到底起到什么作用?事实上,一个拦截器可以看做是一个中间件,它负责拦截我们的请求和响应,并对请求和响应做一些额外的工作,比如为我们请求添加日志,寻找路由,制定连接失败的重试策略为,为响应执行缓存策略等等。总的来说是OkHttp加入拦截器的目的是为了丰富和拓展请求过程使其支持各式各样的需求。
拦截器
为了了解请求的整个过程,我们需要明白拦截器是如何工作的,首先所有的拦截器都是需要实现Interceptor接口的,
1 | public interface Interceptor { |
为了了解拦截器的执行过程,我们需要看看RealInterceptroChain的实现
1 | public final class RealInterceptorChain implements Interceptor.Chain { |
事实上拦截器链的请求过程类似于网络协议栈对于应用数据的处理过程,这里为了解析其工作原理,我们假设有拦截器链A->B->C->D这个链在OKHttp中的表示就是RealInterceptorChain 它实现了拦截器链的proceed方法,主要用来遍历执行拦截器链,开始我们拦截器链的索引为0,也就是从拦截器A开始调用其intercept方法执行拦截器,需要注意的是intercept方法的参数为拦截器链,在A的intercept方法中会通过传递的chain再调用proceed方法,这样每次进入proceed方法就可以inex+1指定链中的下一个拦截器。一直到拦截器D,D不需要再执行chain的proceed方法,因为它是最后一个拦截器,后面没有拦截器了。在OkHttp中拦截器链的最后一个拦截器是CallServerInterceptor,它是真正的执行http请求的地方。